// Copyright 2013 Tumblr, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package vena

import (
	"circuit/kit/xor"
	"encoding/binary"
	"hash/fnv"
)

type Time uint32 // In seconds since epoch

type MetricID    uint32
type PartitionID uint32

type TagSetID    uint32

type SpaceID     uint64

func NewSpaceID(metricID MetricID, tagSetID TagSetID) SpaceID {
	return (SpaceID(metricID) << 32) | SpaceID(tagSetID)
}

func (id SpaceID) ShardKey() xor.Key {
	return xor.Key(id)
}

func (id SpaceID) MetricID() MetricID {
	return MetricID(id >> 32)
}

func (id SpaceID) TagSetID() TagSetID {
	return TagSetID(id & ((1 << 32) - 1))
}

type KeyID    uint16
type ValueID  uint16

type TagSet []Tag

type Tag struct {
	Key   KeyID
	Value ValueID
}

func CompileTagSet(tags map[string]string) TagSet {
	var ts TagSet
	for k, v := range tags {
		ts = append(ts, Tag{Key: HashKey(k), Value: HashValue(v)})
	}
	return ts
}

// HashTagSet
func HashTagSet(tagset TagSet) TagSetID {
	h := fnv.New32a()
	for _, tag := range tagset {
		if err := binary.Write(h, binary.BigEndian, tag); err != nil {
			panic(err)
		}
	}
	return TagSetID(h.Sum32())
}

// HashMetric
func HashMetric(s string) MetricID {
	h := fnv.New32a()
	h.Write([]byte(s))
	return MetricID(h.Sum32())
}

// HashPartition
func HashPartition(s string) PartitionID {
	h := fnv.New32a()
	h.Write([]byte(s))
	return PartitionID(h.Sum32())
}

// HashKey
func HashKey(s string) KeyID {
	h := fnv.New32a()
	h.Write([]byte(s))
	return KeyID(h.Sum32())
}

// HashValue
func HashValue(s string) ValueID {
	h := fnv.New32a()
	h.Write([]byte(s))
	return ValueID(h.Sum32())
}

// HashSpace
func HashSpace(metric string, tagset TagSet) SpaceID {
	return NewSpaceID(HashMetric(metric), HashTagSet(tagset))
}

// Aggregation identifies the type of a statistic
type Aggregation byte

const (
	SUM Aggregation = iota
	AVG
	MIN
	MAX
)
